/*
 * @Author: Jimmy
 * @LastModifiedBy: Jimmy
 * @Date: 2024-05-23 19:54:12
 * @LastEditTime: 2024-09-07 20:42:10
 * @FilePath: /nest_study/server/src/main.ts
 */
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import rateLimit from 'express-rate-limit';
import helmet from 'helmet';
import { mw as requestIpMw } from 'request-ip'
import { ConfigService } from '@nestjs/config';
import { ExceptionsFilter } from './common/filters/exceptions-filter';
import { HttpExceptionsFilter } from './common/filters/http-exceptions-filter';
import { MYValidationPipe } from './common/pipes/validation.pipe';
import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston';
import { LoggingInterceptor } from './common/decorators/logger-intercaptor';
import { BaseExceptionsFilter } from './common/filters/base-exception.filter';
import { ValidationPipe } from '@nestjs/common';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { cors: true});
  
  const config = app.get(ConfigService)
  //设置访问频率
  app.use(
    rateLimit({
      windowMs: 15 * 60 * 1000,//15分钟
      max: 5000,//限制15分钟内最多访问5000次
    })
  )
  // 设置 api 访问前缀
  const prefix: string = config.get<string>('app.prefix') || '/api';
  app.setGlobalPrefix(prefix);
  // 全局替换日志系统
  app.useLogger(app.get(WINSTON_MODULE_NEST_PROVIDER));
  // 对全局的接口 请求 进行日志记录
  app.useGlobalInterceptors(new LoggingInterceptor());
  app.useGlobalInterceptors(new BaseExceptionsFilter());
  app.useGlobalPipes(new MYValidationPipe())
  app.useGlobalPipes(new ValidationPipe({transform:true}))
  app.useGlobalFilters(new ExceptionsFilter());
  app.useGlobalFilters(new HttpExceptionsFilter());
  // web 安全，防常见漏洞
  // 注意： 开发环境如果开启 nest static module 需要将 crossOriginResourcePolicy 设置为 false 否则 静态资源 跨域不可访问
  app.use(helmet({ crossOriginOpenerPolicy: { policy: 'same-origin-allow-popups' }, crossOriginResourcePolicy: false }));
  //swagger配置使用
  const name = config.get<string>('app.name') || 'Admin';
  const version = config.get<string>('app.version') || '1.0.0';
  const port = config.get<number>('app.port') || 8088;

  const swaggerOptions = new DocumentBuilder()
    .setTitle(name)
    .setDescription(`${name}接口文档`)
    .setVersion(version)
    .addBearerAuth()
    .build();
  const document = SwaggerModule.createDocument(app, swaggerOptions);
  // 项目依赖当前文档功能，最好不要改变当前地址
  // 生产环境使用 nginx 可以将当前文档地址 屏蔽外部访问
  SwaggerModule.setup(`${prefix}/swagger-ui`, app, document, {
    swaggerOptions: {
      persistAuthorization: true
    },
    customSiteTitle: `${name} Api Docs`
  })
  //获取用户IP  
  app.use(requestIpMw({ attributeName: 'ip' }));
  //运行（端口）
  await app.listen(port);
  console.log(`\x1B[33m服务启动成功\x1B[0m`, '\n',
    '\x1B[42m 服务地址\x1B[0m', `\x1B[32m\x1B[4mhttp://localhost:${port}${prefix}/\x1B[0m`, '\n',
    '\x1B[44m swagger \x1B[0m', `\x1B[32m\x1B[4mhttp://localhost:${port}${prefix}/swagger-ui/\x1B[0m`);
}
bootstrap();

